#include <iostream>

// Целочисленный логарифм по модулю 2
template < unsigned n >
struct log2 {
	
	// Логарифм нуля не существует
	static_assert(n != 0, "Logarithm of zero does not exists.");
	
	// Используем рекуррентную формулу
	// $\lfloor log_2 n \rfloor = 1 + \lfloor log_2 \frac n2 \rfloor$
	static const unsigned value = 1 + log2< n / 2 >::value;
	
};

// Базис рекуррентности для вычисления целочисленного логарифма
// по модулю 2
template < >
struct log2<1> {

	// Логарифм единицы равен нулю
	static const unsigned value = 0;
	
};

// Возведение в степень
template < unsigned b, unsigned n >
struct pow {
	
	// Используем рекуррентно дихотомический метод
	static const unsigned value =
		( n % 2 == 1 ? b : 1 ) * pow< b * b, n / 2 >::value
	;
	
};

// Базис рекуррентности для вычисления степени
template < unsigned b >
struct pow<b, 0> {
	
	// Любое значение в степени ноль равняется единице
	static const unsigned value = 1;
	
};

const size_t char_size_in_bits = 8;

// Класс вычетов по модулю p
template<unsigned p>
class Z {
	
	// Для результата умножения требуется в два раза больше бит,
	// чем для самого значения.
	static_assert(
		2 * p < sizeof(unsigned) * char_size_in_bits,
		"Too big base p for class Z<p>."
	);
	
	private:
	
		// Хранимое значение по модулю p
		unsigned val;
	
	public:
	
		// Основание системы вычетов
		static const unsigned base = p;
	
		// Конструктор из беззнакового значения
		explicit Z(unsigned v_) : val(v_ % p) {}
	
		// Преобразование к беззнаковому значению
		unsigned value() const { return val; }
		
		// Неявное преобразование к беззнаковому значению
		operator unsigned() const { return val; }
	
		// Операция присваивающего сложения по модулю p
		Z<p> operator+=(const Z<p>& z) {
			val += z.val;
			val %= p;
			return *this;
		}
	
		// Операция присваивающего вычитания по модулю p
		Z<p> operator-=(const Z<p>& z) {
			val += p - z.val;
			val %= p;
			return *this;
		}
	
		// Операция присваивающего умножения по модулю p
		Z<p> operator*=(const Z<p>& z) {
			val *= z.val;
			val %= p;
			return *this;
		}
	
}; // Конец класса

// Операция сложения по модулю p
template<unsigned p>
Z<p> operator+(Z<p> x, Z<p> y) {
	Z<p> z(x);
	return z += y;
}

// Операция вычитания по модулю p
template<unsigned p>
Z<p> operator-(Z<p> x, Z<p> y) {
	Z<p> z(x);
	return z -= y;
}

// Операция умножения по модулю p
template<unsigned p>
Z<p> operator*(Z<p> x, Z<p> y) {
	Z<p> z(x);
	return z *= y;
}

template < class F, size_t n, class value_type = typename F::value_type > class brackets;
template < class F, class value_type >
struct brackets<F,0,value_type> {
	value_type operator() () {
		size_t index = 0;
		return static_cast<F*>(this)->operator[](index);
	}
};
template < class F, class value_type >
struct brackets<F,1,value_type> {
	value_type operator() ( value_type x ) {
		size_t index = x;
		return static_cast<F*>(this)->operator[](index);
	}
};

/**
 * Класс $p$-значной функции, задающейся вектором
 * 
 * Шаблонные параметры:
 *   $Z$ --- кольцо вычетов
 *   $n$ --- размерность функции
 */ 
template<class Z, size_t n>
class function_by_vector : public brackets<function_by_vector<Z, n>, n, Z> {
	
	private:
	
		// Число бит для размещения одного значения
		static const unsigned bits_per_value = 1 + log2<Z::base>::value;
		
		// Маска для выделения битов, хранящих одно значение
		static const unsigned value_mask = (1 << bits_per_value) - 1;
		
		// Количество значений, которые могут разместиться
		// в одном элементе массива.
		static const unsigned values_per_item =
			sizeof(unsigned) / sizeof(char) * char_size_in_bits / bits_per_value
		;
		
		// Число значений в векторе, задающем функцию
		static const size_t size = pow<Z::base, n>::value;
		
		// Массив для хранения вектора значений
		unsigned items[ size / values_per_item ];
		
	public:
		
		// Размерность функции
		static const size_t dim = n;
		
		// Тип значения, хранимого в векторе функции
		typedef Z value_type;
		
		// Получение значения по позиции в векторе
		Z operator[] (size_t i) const {
			return Z(value_mask & (
				items[i / values_per_item]
				>> (i % values_per_item * bits_per_value)
			));
		}
		
		// Установка значения в позицию вектора
		void set(size_t i, const Z value) {
			std::cout << std::hex << items[i / values_per_item] << std::endl;
			items[i / values_per_item] &=
				~(value_mask << (i % values_per_item * bits_per_value))
			;
			std::cout << std::hex << items[i / values_per_item] << std::endl;
			items[i / values_per_item] |=
				value << (i % values_per_item * bits_per_value)
			;
			std::cout << std::hex << items[i / values_per_item] << std::endl;
		}
		
		// Класс ссылки на значение в векторе
		class reference_type {
			private:
				function_by_vector<Z, n>& reference_to_function;
				size_t index;
			public:
				reference_type(function_by_vector<Z, n>& f_ref, size_t i)
					: reference_to_function(f_ref), index(i) {}
				operator Z() const {
					return reference_to_function[index];
				}
				reference_type& operator=(const Z value) {
					reference_to_function.set(index, value);
					return *this;
				}
				reference_type& operator+=(const Z value) {
					Z tmp = *this;
					tmp += value;
					reference_to_function.set(tmp);
					return *this;
				}
				reference_type& operator*=(const Z value) {
					Z tmp = *this;
					tmp *= value;
					reference_to_function.set(tmp);
					return *this;
				}
				reference_type& operator-=(const Z value) {
					Z tmp = *this;
					tmp -= value;
					reference_to_function.set(tmp);
					return *this;
				}
				reference_type& operator/=(const Z value) {
					Z tmp = *this;
					tmp /= value;
					reference_to_function.set(tmp);
					return *this;
				}
		};
		
		// Получение ссылки на позицию в векторе
		// для последующего изменения
		reference_type operator[] (size_t i) {
			return reference_type(*this, i);
		}
		
}; // Конец класса

template < class Z, size_t n >
std::istream& operator >> ( std::istream& in, function_by_vector<Z, n>& f ) {
	const size_t vector_size = pow<Z::base, n>::value;
	for ( size_t i = 0; i < vector_size; ++i ) {
		char c;
		in >> c;
		if ( '0' <= c && c <= '9' )
			f[i] = Z(c - '0');
		if ( 'A' <= c && c <= 'Z' )
			f[i] = Z(c - 'A');
		if ( 'a' <= c && c <= 'z' )
			f[i] = Z(c - 'a');
	}
	return in;
}

template < class Z, size_t n >
std::ostream& operator << ( std::ostream& out, const function_by_vector<Z, n>& f ) {
	const size_t vector_size = pow<Z::base, n>::value;
	for ( size_t i = 0; i < vector_size; ++i ) {
		if ( Z::base <= 10 || f[i] < 10 )
			out << '0' + f[i];
		else
			out << 'A' + f[i];
	}
	return out;
}

int main() {
	function_by_vector<Z<3>,1> v;
	std::cin >> v;
	std::cout << v << std::endl;
	return 0;
}

